﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using iNet.IO;
using iNet.Net;
using iNet.Tasks;

namespace iNet.Media.Imaging
{
	/// <summary>
	/// 通用影像解碼工作。
	/// </summary>
	public class GenericImageDecodeTask : ImageDecodeTask
	{
		#region 靜態欄位
		//static readonly FileCache<Uri> _FileCache = new FileCache<Uri>(Path.GetTempPath(), 64 * 1024 * 1024);
		#endregion
		#region 欄位
		IMediaFormat _DecodingFormat;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 GenericImageDecodeTask 執行個體。
		/// </summary>
		public GenericImageDecodeTask()
			: base(null, null, MediaDecodeRequests.All, ImageDecodeRequests.All)
		{ }
		/// <summary>
		/// 初始化新的 GenericImageDecodeTask 執行個體。
		/// </summary>
		/// <param name="source">影像儲存來源。</param>
		public GenericImageDecodeTask(MediaStorage source)
			: base(null, source, MediaDecodeRequests.All, ImageDecodeRequests.All)
		{ }
		/// <summary>
		/// 初始化新的 GenericImageDecodeTask 執行個體。
		/// </summary>
		/// <param name="source">影像儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="imageDecodeReqs">影像解碼請求。</param>
		public GenericImageDecodeTask(MediaStorage source, MediaDecodeRequests mediaDecodeReqs, ImageDecodeRequests imageDecodeReqs)
			: base(null, source, mediaDecodeReqs, imageDecodeReqs)
		{ }
		#endregion
		#region Decode
		/// <summary>
		/// 解碼影像。
		/// </summary>
		/// <param name="version">工作版本。</param>
		/// <param name="source">影像儲存來源。</param>
		/// <param name="mediaDecodeReqs">媒體解碼請求。</param>
		/// <param name="imageDecodeReqs">影像解碼請求。</param>
		/// <returns>True 表示解碼完成，False 表示解碼失敗。</returns>
		protected override bool Decode(TaskVersion version, MediaStorage source, MediaDecodeRequests mediaDecodeReqs, ImageDecodeRequests imageDecodeReqs)
		{
			string fileName = null;
			Stream stream = null;
			MediaStorage originalSource = source;
			try
			{
				//取得來源檔案或資料流
				if (source.StorageType == MediaStorageType.Stream && source.Stream.CanRead && source.Stream.CanSeek)
				{
					stream = source.Stream;
					source = new MediaStorage(stream);
					this.ReportProgress(version, 50);
				}
				else if (this.GetMediaStorageFile(version, source, 50, out fileName))
					source = new MediaStorage(fileName);
				else
					throw new MediaDecodeFailedException(MediaDecodeFailedReason.CannotAccessStream);

				//建立解碼工作
				ImageDecodeTask decodeTask;
				if (fileName != null)
					decodeTask = ImageCodecs.CreateDecodeTask(fileName);
				else
					decodeTask = ImageCodecs.CreateDecodeTask(stream);
				if (decodeTask == null)
					return false;

				//取得解碼格式
				this.WriteValue<IMediaFormat>(version, ref _DecodingFormat, decodeTask.DecodingFormat);

				//解碼影像
				double? baseProgress = this.Progress;
				if (baseProgress != null)
				{
					double progressRange = ((100 - baseProgress.Value) / 100);
					decodeTask.ProgressChanged += (sender, e) =>
					{
						this.ReportProgress(version, baseProgress + (e.Progress * progressRange));
					};
				}
				switch (this.ExecuteChildDecodeTask(version, decodeTask))
				{
					case TaskState.Executed:
						this.ReportProgress(version, 100);
						break;
					case TaskState.Canceled:
						return true;
					default:
						return false;
				}

				//完成
				return true;
			}
			finally
			{
				if (fileName != null)
					this.ReleaseMediaStorageFile(version, originalSource, fileName);
			}
		}
		#endregion
		#region DecodingFormat
		/// <summary>
		/// 取得影像解碼格式，Null (Visual Basic 為 Nothing) 表示尚未確認影像格式。
		/// </summary>
		public override IMediaFormat DecodingFormat
		{
			get
			{
				return _DecodingFormat;
			}
		}
		#endregion
		#region ResetOverride
		/// <summary>
		/// 重設工作狀態。
		/// </summary>
		protected override void ResetOverride()
		{
			_DecodingFormat = null;
			base.ResetOverride();
		}
		#endregion
		#region SaveToTempFile
		MediaStorage SaveToTempFile(TaskVersion version, Stream stream)
		{
			//建立暫存檔
			string tempFilePath;
			try
			{
				tempFilePath = Path.GetTempFileName();
			}
			catch
			{
				return null;
			}

			//儲存至暫存檔
			MediaStorage result = null;
			try
			{
				using (FileStream fileStream = new FileStream(tempFilePath, FileMode.Create, FileAccess.Write))
				{
					StreamCopyTask copyTask = new StreamCopyTask(stream, fileStream);
					copyTask.ProgressChanged += (sender, e) =>
					{
						this.ReportProgress(version, e.Progress * 0.5);
					};
					if (this.ExecuteChildTask(version, copyTask) == TaskState.Executed)
						result = new MediaStorage(tempFilePath);
				}
			}
			catch
			{ }
			finally
			{
				//刪除暫存檔
				if (result == null)
				{
					try
					{
						File.Delete(tempFilePath);
					}
					catch
					{ }
				}
			}
			return result;
		}
		#endregion
	}
}
